// basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>

// engine files
#include "GameEngine.h"
#include "Input.h"
#include "EngineData.h"
#include <vld.h>

#include <vld.h>

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

// initialize windows
HWND WinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	HWND hWnd;
    WNDCLASSEX wc;

    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
#ifdef FULLSCREEN_MODE
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
#endif
    wc.lpszClassName = WINDOW_TITLE;

    RegisterClassEx(&wc);

    hWnd = CreateWindowEx(NULL,
                          WINDOW_TITLE,
                          WINDOW_TITLE,                 
#ifdef FULLSCREEN_MODE
						  WS_EX_TOPMOST | WS_POPUP,    // fullscreen values
						  0, 0,
#endif
#ifndef FULLSCREEN_MODE
						  WS_OVERLAPPEDWINDOW,
						  CW_USEDEFAULT, CW_USEDEFAULT,
#endif
                          SCREEN_WIDTH, SCREEN_HEIGHT,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    ShowWindow(hWnd, nCmdShow);
	return hWnd;
}

// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	// Debug console
#ifdef MYAPP_DEBUG_TRACE
	if(AllocConsole())
	{
		freopen("CONOUT$", "wt", stdout);

		SetConsoleTitle(L"Engine : Debug Console");

		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);

		printf("\n");
		printf("Engine vAlpha\nUse 'DbgPrintf' to output to console window\n");
		printf("\n");
	}
#endif

	// initialize window
	HWND hWnd = WinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

	/**                       INITIALIZE OBJECTS                       */

	// Set up Graphics Engine
	DX9Engine* pDX9Engine = DX9Engine::getInstance();
	pDX9Engine->initialize(hWnd);

	// Set up Input
	Input* pInput = Input::getInstance();
	pInput->initialize(hWnd, hInstance);

	// TODO Set up Sound
	
	// Initialize Game
	GameEngine GameEngine;
	GameEngine.initialize(hWnd);
	 
	/**                          TIME SETUP                            */
	// unit of counts
	__int64 prevTimeStamp = 0;
	QueryPerformanceCounter((LARGE_INTEGER*)&prevTimeStamp);
	// counts per sec
	__int64 cntsPerSec = 0;
	QueryPerformanceFrequency((LARGE_INTEGER*)&cntsPerSec);
	// sec per count
	float secsPerCnt = 1.0f/(float)cntsPerSec;
	// current time
	__int64 currTimeStamp = 0;
	// time passed
	float dt = 0;


	/**                          GAME LOOP                             */

    MSG msg;
    while(GameEngine.isRunning())
    {
        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if(msg.message == WM_QUIT)
            break;

		// get current time stamp
		QueryPerformanceCounter((LARGE_INTEGER*)&currTimeStamp);
		dt = (currTimeStamp - prevTimeStamp)*secsPerCnt;

		// Input poll devices
		pInput->pollDevices();
		// Game Engine Update
		GameEngine.update(dt);
		// Call Graphics Engine and Game Engine Render functions
		pDX9Engine->startRender();
		pDX9Engine->startSprite();
		// Game Engine Render
		GameEngine.render();
		pDX9Engine->endSprite();
		// Game Engine Text
		GameEngine.renderText();
		pDX9Engine->endRender();

		// Set previous time stamp
		prevTimeStamp = currTimeStamp;
    }
	// Release all engine objects
	GameEngine.release();
	pDX9Engine->release();
	pInput->release();

	// Unregister window
	UnregisterClass(WINDOW_TITLE, hInstance);

    return msg.wParam;
}


// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
	case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		} break;
	case(WM_KEYDOWN):
		{
			switch(wParam)
			{
				// Escape Key will close the application
				// Remove/Modify this call when creating a real game with menus, etc.
			case VK_F1:
				{
					PostQuitMessage(0);
					break;
				}
			}
		}
	}
	return DefWindowProc (hWnd, message, wParam, lParam);
}